#include <errno.h>
#include <signal.h>

#include <linux/sched.h>
#include <linux/kernel.h>

void release(struct task_struct *p)
{
    int i;

    if (!p)
        return;
    for (i = 1; i < NR_TASKS; i++)
        if (task[i] == p) {
            task[i] = NULL;
            free_page((long)p);
            schedule();
            return;
        }
    panic("trying to release non-existent task");
}

static inline int send_sig(long sig, struct task_struct * p, int priv)
{
    if (!p || sig < 1 || sig > 32)
        return -EINVAL;
    if (priv || (current->euid == p->euid) || suser())
        p->signal |= (1 << (sig - 1));
    else
        return -EPERM;
    return 0;
}

static void tell_father(int pid)
{
    int i;

    if (pid)
        for (i = 0; i < NR_TASKS; i++) {
            if (!task[i])
                continue;
            if (task[i]->pid != pid)
                continue;
            task[i]->signal |= (1 << (SIGCHLD - 1));
            return;
        }
    printk("BAD BAD - no father found\n\r");
    release(current);
}

int do_exit(long code)
{
    int i;
    free_page_tables(get_base(current->ldt[1]), get_limit(0x0f));
    free_page_tables(get_base(current->ldt[2]), get_limit(0x17));
    for (i = 0; i < NR_TASKS; i++)
        if (task[i] && task[i]->father == current->pid) {
            task[i]->father = 1;
            if (task[i]->state == TASK_ZOMBIE)
                (void) send_sig(SIGCHLD, task[1], 1);
        }
    if (last_task_used_math == current)
        last_task_used_math = NULL;
    current->state = TASK_ZOMBIE;
    current->exit_code = code;
    tell_father(current->father);
    schedule();
    return (-1);
}

int sys_exit(int error_code)
{
    return do_exit((error_code & 0xff) << 8);
}
